package com.github.cakin.shiro.chapter19.service;

import com.github.cakin.shiro.chapter19.entity.UrlFilter;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.NamedFilterList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @className: ShiroFilerChainManager
 * @description: ShiroFilerChain 的管理器
 * @date: 2020/5/28
 * @author: cakin
 */
@Service
public class ShiroFilerChainManager {

    /**
     * 注入默认的DefaultFilterChainManager
     *
     *1 当没有配置 动态 URL filterChainManager 的主要数据如下：
     * filters：默认的11个加上配置文件中配置的1个。
     * filterChains：配置有4个。
     *
     * filterChainManager = {CustomDefaultFilterChainManager@6405}
     *  filterChainDefinitionMap = {Ini$Section@6412}  size = 4
     *  loginUrl = "/login"
     *  successUrl = "/"
     *  unauthorizedUrl = "/unauthorized.jsp"
     *  filterConfig = null
     *  filters = {LinkedHashMap@6416}  size = 12
     *   "anon" -> {AnonymousFilter@6432} "anon"
     *   "authc" -> {FormAuthenticationFilter@6434} "authc"
     *   "authcBasic" -> {BasicHttpAuthenticationFilter@6436} "authcBasic"
     *   "logout" -> {LogoutFilter@6438} "logout"
     *   "noSessionCreation" -> {NoSessionCreationFilter@6440} "noSessionCreation"
     *   "perms" -> {PermissionsAuthorizationFilter@6442} "perms"
     *   "port" -> {PortFilter@6444} "port"
     *   "rest" -> {HttpMethodPermissionFilter@6446} "rest"
     *   "roles" -> {RolesAuthorizationFilter@6448} "roles"
     *   "ssl" -> {SslFilter@6450} "ssl"
     *   "user" -> {UserFilter@6452} "user"
     *   "sysUser" -> {SysUserFilter@6454} "sysUser"
     *  filterChains = {LinkedHashMap@6407}  size = 4
     *   "/login" -> {SimpleNamedFilterList@6474}  size = 1
     *   "/logout" -> {SimpleNamedFilterList@6476}  size = 1
     *   "/unauthorized.jsp" -> {SimpleNamedFilterList@6478}  size = 1
     *   "/**" -> {SimpleNamedFilterList@6480}  size = 2
     *2 当配置有1个动态 URL filterChainManager 的主要数据如下：
     * filterChains 多了配置的/organization/** ，它对应的拦截器是role
     * filterChains = {LinkedHashMap@5694}  size = 5
     *  "/login" -> {SimpleNamedFilterList@5774}  size = 1
     *  "/logout" -> {SimpleNamedFilterList@5776}  size = 1
     *  "/unauthorized.jsp" -> {SimpleNamedFilterList@5778}  size = 1
     *  "/**" -> {SimpleNamedFilterList@5780}  size = 2
     *  "/organization/**" -> {SimpleNamedFilterList@5781}  size = 1
     *
     */
    @Autowired
    private DefaultFilterChainManager filterChainManager;

    /**
     * 默认defaultFilterChains
     */
    private Map<String, NamedFilterList> defaultFilterChains;

    /**
     * 功能描述：初始化 defaultFilterChains
     *
     * @author cakin
     * @date 2020/5/28
     * @description: 初始化顺序
     * Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
     * Spring 容器启动时会调用 init 方法把在 spring 配置文件中配置的默认拦截器保存下来，之后会自动与数据库中的配置进行合并。
     */
    @PostConstruct
    public void init() {
        /**
         * defaultFilterChains 的样子，就是配置文件中配的样子
         * "/login" -> {SimpleNamedFilterList@5600}  size = 1
         * "/logout" -> {SimpleNamedFilterList@5602}  size = 1
         * "/unauthorized.jsp" -> {SimpleNamedFilterList@5604}  size = 1
         * "/**" -> {SimpleNamedFilterList@5606}  size = 2
         */
        defaultFilterChains = new HashMap<String, NamedFilterList>(filterChainManager.getFilterChains());
    }

    /**
     * 功能描述：会在 Spring 容器启动或进行增删改 UrlFilter 时进行注册 URL 拦截器到 Shiro
     *
     * @author cakin
     * @date 2020/5/28
     * @param urlFilters 数据库中的 urlFilters 列表
     * @description: filterChains 包含两部分数据
     * 1 配置文件中配置的 urlFilters 列表。
     * 2 数据库中配置的 urlFilters 列表。
     * 该函数的作用是合并这两个urlFilters。
     */
    public void initFilterChains( List<UrlFilter> urlFilters ) {
        // 1、首先删除以前老的filter chain并注册默认的
        Map<String, NamedFilterList> filterChains = filterChainManager.getFilterChains();
        filterChains.clear();
        if (defaultFilterChains != null) {
            filterChainManager.getFilterChains().putAll(defaultFilterChains);
        }

        //2、循环URL Filter（从sys_url_filter数据表获取所有的记录），注册filter chain
        for (UrlFilter urlFilter : urlFilters) {
            String url = urlFilter.getUrl();
            /**
             *  注册roles filter，类似加了下面这条数据到配置文件中
             *  /organization/** = roles[organization]
             *  /organization/** 对应参数 url
             *  roles 对应参数 roles
             *  organization 对应参数 urlFilter.getRoles()
             */
            if (!StringUtils.isEmpty(urlFilter.getRoles())) {
                filterChainManager.addToChain(url, "roles", urlFilter.getRoles());
            }
            //注册perms filter
            if (!StringUtils.isEmpty(urlFilter.getPermissions())) {
                filterChainManager.addToChain(url, "perms", urlFilter.getPermissions());
            }
        }
    }

}
